/**
 * 打印当前函数调用栈
 */
function print_stacks() {
    const Throwable = Java.classFactory.use("java.lang.Throwable")
    let result = "=======调用栈信息=======\n"
    const ex = Throwable.$new()
    const stackElements = ex.getStackTrace()
    if (stackElements) {
        result += stackElements[0] + "\n"
        for (let i = 1; i < stackElements.length; i++) {
            result += "\t" + stackElements[i] + "\n"
        }
    }
    result += "======= Done =======\n"
    console.log(result)
}

/**
 * 打印 HashMap
 * @param map 
 */
function map2str(map, tabNum = 0) {
    let result = "";
    const keyset = map.keySet();
    const it = keyset.iterator();
    while (it.hasNext()) {
        const keystr = it.next().toString();
        const valuestr = map.get(keystr).toString();
        result += "\t".repeat(tabNum)
        result += keystr + ": " + valuestr + "\n"
    }
    if (result == "") {
        return "empty map"
    }
    return result
}

/**
 * 打印ArrayList
 * @param {*} arrayList 
 */
function list2str(arrayList) {
    let result = ""
    const size = arrayList.size()
    for (let i = 0; i < size; i++) {
        const item = arrayList.get(i)
        result += "\t" + item
    }
    if (result) {
        return "\tempty list"
    } else {
        return result
    }
}


/**
 * 根据关键词 搜索类
 * @param clsNameKeyWord 类名关键词
 */
function searchClasses(clsNameKeyWord) {
    Java.enumerateLoadedClasses({
        "onMatch": function (name, handle) {
            if (name.includes(clsNameKeyWord)) {
                console.log(name)
            }
        },
        "onComplete": function () {
            console.log("=== search", clsNameKeyWord, "done ===");
        }
    });
}

/**
 * Enumerates methods matching `query`.
 *
 * @param {string} query Query specified as `class!method`, with globs permitted. May
 *              also be suffixed with `/` and one or more modifiers:
 *              - `i`: Case-insensitive matching.
 *              - `s`: Include method signatures, so e.g. `"putInt"` becomes
 *                `"putInt(java.lang.String, int): void"`.
 *              - `u`: User-defined classes only, ignoring system classes.
 */
function searchMethods(query) {
    let m = Java.enumerateMethods(query)
    console.log(JSON.stringify(m, null, 2))
    debugger
}

/**
 * 根据类名搜索类的实例
 * @param {string} clsName 完整类名
 * @param {boolean} easyMode 是否直接打印对象，默认打印对象完整信息
 */
function searchObject(clsName, easyMode = false) {
    Java.choose(clsName, {
        onMatch: function (instance) {
            if (easyMode) {
                console.log(instance)
            } else {
                printObj(instance)
            }
            debugger
        },
        onComplete: function () {
            console.warn("=======search obj done ========")
        }
    })
}

/**
 * 打印对象的属性
 * [TODO] 对于方法……
 * @param obj 
 */
function printObj(obj) {
    let result = "===" + obj.$className + "===\n"
    obj.$ownMembers.forEach(member => {
        if (obj[member] instanceof Function) { // 方法属性
            result += member + "()\n"
        } else if (obj[member]) {
            result += member + " ==> " + obj[member].value + "\n"
            if (Object.prototype.toString.call(obj[member].value) === '[object Object]') {
                // result += obj[member].value.$className + " ]]]]]]\n"
                result += specialObj_toString(obj[member].value) + "\n"
            }
        } else {
            result += member + " ==> " + "null\n"
        }
    });
    result += "=".repeat(6 + obj.$className.length) + "\n"
    console.log(result)
}

/**
 * 打印特殊obj, 如 HashMap, ArrayList
 * @param {object} obj 
 */
function specialObj_toString(obj) {
    switch (obj.$className) {
        case "java.util.ArrayList":
            return list2str(obj)
        case "java.util.HashMap":
            return map2str(obj)
        default:
            throw "unsupport class:" + obj.$className
    }
}

/**
 * traceMethod 打印单个参数
 * @param {Object} arg 
 */
function printSingleArg(arg) {
    // arg.
}


export { print_stacks, searchClasses, searchMethods, printObj, searchObject }